package cn.elead.it.sso.system.controller;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.Map;

import javax.mail.MessagingException;

import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.gitee.domain.CustomMailMessage;
import com.gitee.elead.web.controller.SuperController;
import com.gitee.service.IEmailService;

import cn.elead.it.sso.core.model.SsoUser;
import cn.elead.it.sso.core.util.RSAUtil;
import cn.elead.it.sso.system.model.PwdRecord;
import cn.elead.it.sso.system.model.User;
import cn.elead.it.sso.system.model.UserPwd;
import cn.elead.it.sso.system.service.IPwdRecordService;
import cn.elead.it.sso.system.service.IUserService;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 密码修改记录控制器
 * 
 * @author luopeng
 *
 */
@Slf4j
@Controller
public class PwdRecordController extends SuperController {

	private static final char EMAIL_CHAR = '@';

	@Value("${spring.mail.username}")
	private String fromMail;

	@Value("${spring.mail.suffix:e-lead.cn}")
	private String emailSuffix = "e-lead.cn";
	
	@Value("${ras.privateKey}")
	private String privateKey;

	@Autowired
	private IUserService userService;

	@Autowired
	private IEmailService emailService;

	@Autowired
	private IPwdRecordService pwdRecordService;

	@RequestMapping("/modfiy/password")
	public String modfiyPasswordHtml(Model model) {
		return "password";
	}

	@RequestMapping("/modfiy/valid")
	public String validHtml(Model model, @RequestParam("sid") String sid, @RequestParam("id") String id) {
		User user = userService.getById(id);
		if (ObjectUtil.isNull(user)) {
			model.addAttribute("errorMsg", "地址参数错误");
			return "valid";
		}
		// 校验当前是否已经登录
		return "newPassword";
	}

	@RequestMapping("/modfiy/newPassword")
	public String newPasswordHtml(Model model, @RequestParam(value = "sid", required = false) String sid,
			@RequestParam(value = "id", required = false) String id) {
		if (StrUtil.isBlank(id)) {
			model.addAttribute("errorMsg", "id参数为空");
			return "valid";
		}
		if (StrUtil.isBlank(sid)) {
			model.addAttribute("errorMsg", "sid参数为空");
			return "valid";
		}
		PwdRecord record = pwdRecordService.query().eq(PwdRecord::getId, id).eq(PwdRecord::getStatus, 2).getOne();
		if (ObjectUtil.isNull(record)) {
			model.addAttribute("errorMsg", "密码已修改完成");
			return "passwordSuccess";
		}

		User user = userService.getById(id);
		// 校验
		String secretKey = record.getValidataCode();
		// 将用户名、过期时间、密钥生成链接密钥
		String key = user.getPinYin() + "$" + record.getOutDate() + "$" + secretKey;
		// 数字签名
		String digitalSignature = Md5Crypt.apr1Crypt(key, user.getId());
		if (!StrUtil.equals(sid, digitalSignature)) {
			model.addAttribute("errorMsg", "数字签名不正确");
			return "password";
		}
		long outDate = record.getOutDate();
		ZoneId zone = ZoneId.systemDefault();
		Instant instant = LocalDateTime.now().atZone(zone).toInstant();
		long epochMilli = instant.toEpochMilli();
		if (epochMilli > outDate) {
			model.addAttribute("errorMsg", "已经过期,请重新修改");
			return "password";
		}
		model.addAttribute("id", id);
		model.addAttribute("sid", sid);
		model.addAttribute("username", user.getUserName());
		// 校验当前是否已经登录
		return "newPassword";
	}

	@Transactional
	@PostMapping("/modfiy/newPassword")
	public String newPassword(Model model, @ModelAttribute UserPwd userPwd) throws Exception {

		String id = userPwd.getId();
		String sid = userPwd.getSid();
		String password = userPwd.getPassword();
		String newPassword = userPwd.getNewPassword();
		if (StrUtil.isBlank(id)) {
			model.addAttribute("errorMsg", "id参数为空");
			return "valid";
		}
		if (StrUtil.isBlank(sid)) {
			model.addAttribute("errorMsg", "sid参数为空");
			return "valid";
		}

		if (StrUtil.isBlank(password)) {
			model.addAttribute("id", id);
			model.addAttribute("sid", sid);
			User user = userService.getById(id);
			model.addAttribute("username", user.getUserName());
			model.addAttribute("errorMsg", "密码不为空");
			return "newPassword";
		}

		int length = password.length();
		if (length < 6 || length > 20) {
			model.addAttribute("id", id);
			model.addAttribute("sid", sid);
			User user = userService.getById(id);
			model.addAttribute("username", user.getUserName());
			model.addAttribute("errorMsg", "密码长度在 6 到 20 个字符");
			return "newPassword";
		}

		if (!password.equals(newPassword)) {
			model.addAttribute("id", id);
			model.addAttribute("sid", sid);
			User user = userService.getById(id);
			model.addAttribute("username", user.getUserName());
			model.addAttribute("errorMsg", "密码不一致");
			return "newPassword";
		}

		PwdRecord record = pwdRecordService.query().eq(PwdRecord::getId, id).eq(PwdRecord::getStatus, 2).getOne();
		if (ObjectUtil.isNull(record)) {
			model.addAttribute("errorMsg", "密码已修改完成");
			return "passwordSuccess";
		}

		User user = userService.getById(id);
		// 校验
		String secretKey = record.getValidataCode();
		// 将用户名、过期时间、密钥生成链接密钥
		String key = user.getPinYin() + "$" + record.getOutDate() + "$" + secretKey;
		// 数字签名
		String digitalSignature = Md5Crypt.apr1Crypt(key, user.getId());
		if (!StrUtil.equals(sid, digitalSignature)) {
			model.addAttribute("errorMsg", "数字签名不正确");
			return "password";
		}
		long outDate = record.getOutDate();
		ZoneId zone = ZoneId.systemDefault();
		Instant instant = LocalDateTime.now().atZone(zone).toInstant();
		long epochMilli = instant.toEpochMilli();
		if (epochMilli > outDate) {
			model.addAttribute("errorMsg", "已经过期,请重新修改");
			return "password";
		}

		// 修改密码
		password = RSAUtil.encryptByPrivateKey(password, privateKey);
		userService.update().set(User::getPassword, password)
				.set(User::getPasswordStatus, 1).eq(User::getId, id).execute();
		pwdRecordService.update().set(PwdRecord::getStatus, 4).eq(PwdRecord::getId, id).execute();

		return "passwordSuccess";

	}

	@PostMapping("/modfiy/password")
	public String modfiyPassword(Model model, @ModelAttribute SsoUser user) throws MessagingException {

		String account = user.getEmail();
		if (StrUtil.isBlank(account)) {
			model.addAttribute("errorMsg", "请输入邮箱");
			return "password";
		}
		if (StrUtil.contains(account, EMAIL_CHAR)) {
			account = StrUtil.subBefore(user.getEmail(), EMAIL_CHAR, true);
		}
		if (StrUtil.isBlank(account)) {
			model.addAttribute("errorMsg", "请输入正确格式");
			return "password";
		}
		User one = userService.query().eq(User::getAccount, account).or().eq(User::getId, account).getOne();
		if (ObjectUtil.isNull(one)) {
			model.addAttribute("errorMsg", "请输入正确账号信息");
			return "password";
		}

		// 发送邮件
		CustomMailMessage message = new CustomMailMessage();
		message.setFrom(fromMail);
		String to = account + EMAIL_CHAR + emailSuffix;
		log.info("to:{}", to);
		message.setTo(to);

		String link = createLink(one);
		log.info("link:{}", link);
		Map<String, Object> variables = new HashMap<String, Object>();
		variables.put("name", one.getUserName());
		variables.put("link", link);

		message.setVariables(variables);
		emailService.sendHtmlMail(message);
		// 邮件发送成功
		if (message.isIfSuccess()) {
			model.addAttribute("email", account + EMAIL_CHAR + emailSuffix);
			model.addAttribute("errorMsg", "邮件已发送,请查收");
			return "valid";
		}
		// 邮件发送失败
		model.addAttribute("errorMsg", "邮件发送失败");
		return "password";
	}

	/**
	 * @Description: 生成邮箱链接地址
	 * @author luopeng
	 * @date 2016-11-3 下午01:50:14
	 */
	public String createLink(User user) {
		// 此处应该更新record表中的过期时间、密钥信息
		PwdRecord record = new PwdRecord();
		record.setId(user.getId());
		record.setStatus(2);
		// 设置过期时间,30分钟后过期
		LocalDateTime date = LocalDateTime.now().plusMinutes(30);
		// 生成密钥
		String secretKey = IdUtil.fastSimpleUUID();
		record.setValidataCode(secretKey);
		// 将用户名、过期时间、密钥生成链接密钥
		ZoneId zone = ZoneId.systemDefault();
		Instant instant = date.atZone(zone).toInstant();
		long epochMilli = instant.toEpochMilli();
		String key = user.getPinYin() + "$" + epochMilli + "$" + secretKey;
		record.setOutDate(epochMilli);
		// 数字签名
		String digitalSignature = Md5Crypt.apr1Crypt(key, user.getId());

		String path = request.getContextPath();
		String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path;
		String resetPassHref = basePath + "/modfiy/newPassword?sid=" + digitalSignature + "&id=" + user.getId();

		pwdRecordService.saveOrUpdate(record);

		return resetPassHref;

	}

}